#include "zookeeperutil.h"
#include "mprpcapplication.h"
#include <iostream>

// 全局watcher观察器
void global_watcher(zhandle_t* zh, int type,
                    int state, const char* path, void* watcherCtx) {
    if (type == ZOO_SESSION_EVENT) {    // 回调消息类型
        if (state == ZOO_CONNECTED_STATE) {
            sem_t* sem = (sem_t*)zoo_get_context(zh);
            sem_post(sem); // 信号量 + 1
        }
    }
}

ZkClient::ZkClient()
: m_zhandle(nullptr)
{ }

ZkClient::~ZkClient() {
    if (m_zhandle != nullptr) {
        zookeeper_close(m_zhandle); // 关闭句柄，释放资源
    }
}

void ZkClient::Start() {
    std::string host = MprpcApplication::GetInstance().GetConfing().Load("zookeeperip");
    std::string port = MprpcApplication::GetInstance().GetConfing().Load("zookeeperport");
    std::string connstr = host + ":" + port;

    /*
     * 多线程版本
     * API调用线程
     * 网络IO线程   poll
     * watcher回调线程
     */ 
    m_zhandle = zookeeper_init(connstr.c_str(), global_watcher, 30000, nullptr, nullptr, 0);
    if (nullptr == m_zhandle) {
        std::cout << "zookeeper_init error!" << std::endl;
        exit(EXIT_FAILURE);
    }

    sem_t sem;
    sem_init(&sem, 0, 0);
    zoo_set_context(m_zhandle, &sem);

    sem_wait(&sem);
    std::cout << "zookeeper_init success!" << std::endl;
}

void ZkClient::Create(const char* path, const char* data, int datalen, int state) {
    char path_buffer[128];
    int bufferlen = sizeof(path_buffer);
    int flag;
    // 先判断path路径的节点是否存在
    flag = zoo_exists(m_zhandle, path, 0, nullptr);
    if (flag == ZNONODE) {  
        // 不存在，开始创建
        flag = zoo_create(m_zhandle, path, data, datalen,
                            &ZOO_OPEN_ACL_UNSAFE, state, path_buffer, bufferlen);
        if (flag == ZOK) {
            std::cout << "znode create success... path:" << path << std::endl;
        }
        else {
            std::cout << "flag:" << flag << std::endl;
            std::cout << "znode create error... path" << path << std::endl;
            exit(EXIT_FAILURE); 
        }
    }
}

std::string ZkClient::GetData(const char* path) {
    char buffer[64];
    int bufferlen = sizeof(buffer);
    int flag = zoo_get(m_zhandle, path, 0, buffer, &bufferlen, nullptr);
    if (flag != ZOK) {
        std::cout << "get znode error... path:" << path << std::endl;
        return "";
    }
    else {
        return buffer;
    }
}